package com.snow.sdfffff

import android.annotation.SuppressLint
import android.app.ActivityManager
import android.os.Build
import android.util.Log
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy

/**
 * Created by zhaoyingtao
 * Date: 2020/12/14
 * Describe:修复ActivityRecord not found问题
 * 使用，在application中调用IActivityManagerHook.INSTANCE.iActivityManagerHook();
 */
object IActivityManagerHook {
    private const val TAG = "IActivityManagerHook"

    @SuppressLint("PrivateApi")
    fun  iActivityManagerHook() {
        Log.w(TAG, "========Build.VERSION.SDK_INT============"+Build.VERSION.SDK_INT)
        if (Build.VERSION.SDK_INT < 24 || Build.VERSION.SDK_INT > 28) {
            return
        }
        try {
            val singletonCls = Class.forName("android.util.Singleton")
            // 第一步：通过反射拿到Singleton对象
            val iActivityManagerSingleton = if (Build.VERSION.SDK_INT <= 25) {
                getIActivityManagerSingletonInstanceN(singletonCls)
            } else {
                getIActivityManagerSingletonInstance(singletonCls)
            } ?: return
            // 第二步：找出Singleton里的mInstance变量
            val instanceField = singletonCls.getDeclaredField("mInstance")
            instanceField.isAccessible = true
            val iActivityManager = instanceField.get(iActivityManagerSingleton)
            if (iActivityManager == null) {
                Log.w(TAG, "Not found IActivityManager instance.")
                return
            }

            // 第三步：使用动态代理替换原来的IActivityManager对象
            val proxy = IActivityManagerProxy(iActivityManager)
            val iActivityManagerCls = Class.forName("android.app.IActivityManager")
            val iActivityManageProxy = Proxy.newProxyInstance(iActivityManagerCls.classLoader, arrayOf(iActivityManagerCls), proxy)
            instanceField.set(iActivityManagerSingleton, iActivityManageProxy)
            Log.w(TAG, "IActivityManager hook success.")
        } catch (e: Throwable) {
            Log.w(TAG, "IActivityManager hook fail: $e")
        }
    }

    @SuppressLint("PrivateApi")
    private fun getIActivityManagerSingletonInstanceN(singletonCls: Class<*>): Any? {
        // 找到ActivityManagerNative里的gDefault这个常量
        // 这里通过变量的类型对比找出gDefault这个常量，
        // 没有通过名字来查找，防止名字有变法
        // 这里也可以直接使用activityManagerNativeCls.getDeclaredField("gDefault")来获取
        val activityManagerNativeCls = Class.forName("android.app.ActivityManagerNative")
        var iActivityManagerSingleton: Any? = null
        for (field in activityManagerNativeCls.declaredFields) {
            if (field.type == singletonCls) {
                field.isAccessible = true
                iActivityManagerSingleton = field.get(null)
                break
            }
        }
        if (iActivityManagerSingleton == null) {
            Log.w(TAG, "Not found IActivityManager singleton field in class ActivityManagerNative.")
        }

        return iActivityManagerSingleton
    }

    private fun getIActivityManagerSingletonInstance(singletonCls: Class<*>): Any? {
        // 找到ActivityManager里的IActivityManagerSingleton常量
        // 这里通过变量的类型对比找出IActivityManagerSingleton这个常量，
        // 没有通过名字来查找，防止名字有变法
        // 这里也可以直接使用ActivityManager::class.java.getDeclaredField("IActivityManagerSingleton")来获取
        var iActivityManagerSingleton: Any? = null
        for (field in ActivityManager::class.java.declaredFields) {
            if (field.type == singletonCls) {
                field.isAccessible = true
                iActivityManagerSingleton = field.get(null)
                break
            }
        }
        if (iActivityManagerSingleton == null) {
            Log.w(TAG, "Not found IActivityManager singleton field in class ActivityManager.")
        }

        return iActivityManagerSingleton
    }

    private class IActivityManagerProxy(private val instance: Any) : InvocationHandler {
        override fun invoke(proxy: Any?, method: Method, args: Array<out Any>?): Any? {
            Log.w(TAG, "invoke: ${method.name}()")
            if (method.name == "isTopOfTask") {
                return try {
                    val result = method.invoke(instance, *(args ?: emptyArray())) as Boolean
                    Log.w(TAG, "isTopOfTask() invoke success")
                    result
                } catch (e: Exception) {
                    Log.w(TAG, "isTopOfTask() invoke exception: $e")
                    false
                }
            }
            return method.invoke(instance, *(args ?: emptyArray()))
        }
    }
}